import { ForbiddenException, Injectable } from '@nestjs/common';
import { CreateLessonsSortDto } from './dto/create-lessons-sort.dto';
import { UpdateLessonsSortDto } from './dto/update-lessons-sort.dto';
import { In, Repository } from 'typeorm';
import { LessonsSort } from './entities/lessons-sort.entity';
import { InjectRepository } from '@nestjs/typeorm';
import { TimeSlotsService } from '../time-slots/time-slots.service';
import { GetLessonsSortDto } from './dto/get-lessons-sort.dto';
import { conditionUtilsLike } from '../utils/db.help';

@Injectable()
export class LessonsSortService {
  constructor(
    private readonly timeSlotsService: TimeSlotsService,
    @InjectRepository(LessonsSort)
    private lessonsSortRepository: Repository<LessonsSort>,
  ) {}

  async create(createLessonsSortDto: CreateLessonsSortDto) {
    try {
      await this.isCreatedConflict(createLessonsSortDto);
      const list = await this.timeSlotsService.returnTimeSlotsEntities(
        createLessonsSortDto.timeSlotsId,
      );
      createLessonsSortDto.timeSlots = list;
      const res = await this.lessonsSortRepository.save(createLessonsSortDto);
      if (res.id) {
        return this.findDetail(res.id);
      }
    } catch (error) {
      return new ForbiddenException(error.message);
    }
  }

  async findAll(query: GetLessonsSortDto) {
    const { page, limit, class_room_id, course_id, teacher_id, blur } = query;
    const conditions = [
      { field: 'class_room_id', value: class_room_id },
      { field: 'course_id', value: course_id },
      { field: 'teacher_id', value: teacher_id },
    ];
    const queryBuilder =
      this.lessonsSortRepository.createQueryBuilder('lessons_sort');

    let newQueryBuilder = conditionUtilsLike<LessonsSort>(
      queryBuilder,
      conditions,
      'lessons_sort',
    );

    if (blur) {
      newQueryBuilder = newQueryBuilder
        .orWhere('class_room.class_room_name LIKE :searchTerm', {
          searchTerm: `%${blur}%`,
        })
        .orWhere('course.name LIKE :searchTerm', {
          searchTerm: `%${blur}%`,
        })
        .orWhere(
          'teacher.t_name LIKE :searchTerm OR teacher.t_code  LIKE :searchTerm',
          {
            searchTerm: `%${blur}%`,
          },
        );
    }
    const content = await newQueryBuilder
      .leftJoinAndSelect('lessons_sort.classRoom', 'class_room')
      .leftJoinAndSelect('lessons_sort.course', 'course')
      .leftJoinAndSelect('lessons_sort.teacher', 'teacher')
      .leftJoinAndMapMany(
        'lessons_sort.timeSlots',
        'lessons_sort.timeSlots',
        'time_slot',
      )
      .skip((page - 1) * limit || 0)
      .take(limit || 10)
      .getMany();
    const count = await newQueryBuilder.getCount();
    return {
      content,
      totalElements: count,
      totalPages: Number(page || 1),
    };
  }

  async findOne(id: number) {
    return await this.lessonsSortRepository.findOne({ where: { id } });
  }

  async update(id: number, updateLessonsSortDto: UpdateLessonsSortDto) {
    const detail = await this.findDetail(id);
    const newRes = Object.assign({}, detail, updateLessonsSortDto);
    try {
      await this.isUpDateConflict(id, newRes);
      delete newRes.teacher;
      delete newRes.timeSlots;
      delete newRes.classRoom;
      delete newRes.course;
      const res = await this.lessonsSortRepository.save(newRes);
      if (res.id) {
        return this.findDetail(res.id);
      }
    } catch (error) {
      return new ForbiddenException(error.message);
    }
  }

  async remove(id: number) {
    const query = await this.lessonsSortRepository.findOne({
      where: { id },
      relations: ['timeSlots'],
    });
    if (query) {
      return await this.lessonsSortRepository.remove(query);
    } else {
      throw new ForbiddenException('失败');
    }
  }

  async findDetail(id: number): Promise<LessonsSort> {
    const query = this.lessonsSortRepository.createQueryBuilder('lessons_sort');
    const res = await query
      .leftJoinAndSelect('lessons_sort.classRoom', 'class_room')
      .leftJoinAndSelect('lessons_sort.course', 'course')
      .leftJoinAndSelect('lessons_sort.teacher', 'teacher')
      .leftJoinAndMapMany(
        'lessons_sort.timeSlots',
        'lessons_sort.timeSlots',
        'time_slot',
      )
      .where('lessons_sort.id = :id', { id })
      .getOne();
    return res;
  }

  // 判断创建课程是冲突
  async isCreatedConflict(createLessonsSortDto: CreateLessonsSortDto) {
    let flag = false;
    let msg = '';
    /// 老师是否冲突
    const res = await this.lessonsSortRepository
      .createQueryBuilder('lessons_sort')
      .innerJoinAndSelect('lessons_sort.timeSlots', 'time_slot')
      .where('lessons_sort.week = :week', {
        week: createLessonsSortDto.week,
      })
      .getMany();

    if (res.length) {
      try {
        res.forEach((item) => {
          const timeSlots = item.timeSlots.map((s) => s.timeSlot_id);
          let timeSlotsIncludeFlag = false;
          // 时间段是否冲突
          timeSlotsIncludeFlag = timeSlots.some((s) =>
            createLessonsSortDto.timeSlotsId.includes(s),
          );
          // 教室与时间段
          if (
            createLessonsSortDto.class_room_id === item.class_room_id &&
            timeSlotsIncludeFlag
          ) {
            throw `${createLessonsSortDto.week}此时间段的教室，已安排课程`;
          }

          // 教师与时间段
          if (
            createLessonsSortDto.teacher_id === item.teacher_id &&
            timeSlotsIncludeFlag
          ) {
            throw `${createLessonsSortDto.week}此时间段的老师，已安排课程`;
          }
        });
      } catch (error) {
        flag = true;
        msg = error;
      }
    }
    if (flag) {
      throw new ForbiddenException(msg);
    }
  }

  // 判断更新课程是否冲突
  // 更新 先查出除自己外以为的排课，在查出自己的排课
  async isUpDateConflict(
    lessonsSortId: number,
    createLessonsSortDto: CreateLessonsSortDto,
  ) {
    let otherFlag = false;
    let myFlag = false;
    let msg = '';

    // 除自己外以为的排课
    const otherRes = await this.lessonsSortRepository
      .createQueryBuilder('lessons_sort')
      .innerJoinAndSelect('lessons_sort.timeSlots', 'time_slot')
      .where('lessons_sort.week = :week', {
        week: createLessonsSortDto.week,
      })
      .andWhere('lessons_sort.teacher_id != :teacherId', {
        teacherId: createLessonsSortDto.teacher_id,
      })
      .getMany();

    if (otherRes.length) {
      try {
        otherRes.forEach((item) => {
          const timeSlots = item.timeSlots.map((s) => s.timeSlot_id);
          let timeSlotsIncludeFlag = false;
          // 时间段是否冲突
          timeSlotsIncludeFlag = timeSlots.some((s) =>
            createLessonsSortDto.timeSlotsId.includes(s),
          );
          // 教室与时间段
          if (
            createLessonsSortDto.class_room_id === item.class_room_id &&
            timeSlotsIncludeFlag
          ) {
            throw `${createLessonsSortDto.week}此时间段的教室，已安排课程`;
          }

          // 教师与时间段
          if (
            createLessonsSortDto.teacher_id === item.teacher_id &&
            timeSlotsIncludeFlag
          ) {
            throw `${createLessonsSortDto.week}此时间段的老师，已安排课程`;
          }
        });
      } catch (error) {
        otherFlag = true;
        msg = error;
      }
      if (otherFlag) {
        throw new ForbiddenException(msg);
      }
    }

    if (!otherFlag) {
      // 自己的排课
      const myrRes = await this.lessonsSortRepository
        .createQueryBuilder('lessons_sort')
        .innerJoinAndSelect('lessons_sort.timeSlots', 'time_slot')
        .where('lessons_sort.week = :week', {
          week: createLessonsSortDto.week,
        })
        .andWhere('lessons_sort.teacher_id = :teacherId', {
          teacherId: createLessonsSortDto.teacher_id,
        })
        .andWhere('lessons_sort.id != :id', {
          id: lessonsSortId,
        })
        .getMany();

      if (myrRes.length) {
        try {
          myrRes.forEach((item) => {
            const timeSlots = item.timeSlots.map((s) => s.timeSlot_id);
            let timeSlotsIncludeFlag = false;
            // 时间段是否冲突
            timeSlotsIncludeFlag = timeSlots.some((s) =>
              createLessonsSortDto.timeSlotsId.includes(s),
            );
            // 教室与时间段
            if (
              createLessonsSortDto.class_room_id === item.class_room_id &&
              timeSlotsIncludeFlag
            ) {
              throw `${createLessonsSortDto.week}此时间段的教室，已安排课程`;
            }

            // 教师与时间段
            if (
              createLessonsSortDto.teacher_id === item.teacher_id &&
              timeSlotsIncludeFlag
            ) {
              throw `${createLessonsSortDto.week}此时间段的老师，已安排课程`;
            }
          });
        } catch (error) {
          myFlag = true;
          msg = error;
        }
      }
      if (myFlag) {
        throw new ForbiddenException(msg);
      }
    }
  }

  // 返回实体
  async returnLessonsSortEntities(ids: number[]) {
    return await this.lessonsSortRepository.find({
      where: {
        id: In(ids),
      },
    });
  }
}
